﻿using GPDWin4GameBarPowerBackend.AIO.ServiceMain;
using Newtonsoft.Json;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.UI.WebControls;
using System.Windows.Forms;
using Vanara.PInvoke;
using static Vanara.PInvoke.User32;

namespace GPDWin4GameBarPowerBackend.AIO.ForegroundChangedHelper
{
    public static class Program
    {
        public const string type = "fgnotify";
        public const string pipeId = "GPDFGNotify_019857CF75174F77B617CB69DA555FEC";

        private static NamedPipeClientStream client;
        private static StreamWriter sw;

        public static void Main()
        {
            Console.WriteLine("Foreground Monitoring Process Started. ");
            client = new NamedPipeClientStream(pipeId);
            client.Connect();

            Console.WriteLine("Server Connected. ");
            sw = new StreamWriter(client);
            eventWaitHandle = new EventWaitHandle(true, EventResetMode.AutoReset);
            new Thread(NotifyThread).Start();

            SetWinEventHook(
                EventConstants.EVENT_SYSTEM_FOREGROUND, EventConstants.EVENT_SYSTEM_FOREGROUND,
                HINSTANCE.NULL, WinEventProc,
                0, 0,
                WINEVENT.WINEVENT_OUTOFCONTEXT | WINEVENT.WINEVENT_SKIPOWNPROCESS);

            Console.WriteLine("Setting hooks.");



            // 开启消息循环，以便 WinEventProc 能够被调用。
            Application.Run();
        }

        private static void NotifyThread()
        {
            string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows).ToLower();
            while (eventWaitHandle.WaitOne())
            {
                Thread.Sleep(100);
                var current = GetForegroundWindow();
                var w = new Win32Window(current);
                var json = new CurrentForegroundWindow()
                {
                    WindowTitle = w.Title,
                    ProcessPath = w.ProcessName.ToLower(),
                };
                if (json.ProcessPath.StartsWith(windir))
                {
                    json.WindowTitle = "无";
                    json.ProcessPath = null;
                }
                if (string.IsNullOrWhiteSpace(json.WindowTitle))
                {
                    json.WindowTitle = w.ProcessName;
                }
                try
                {
                    sw.WriteLine(JsonConvert.SerializeObject(json));
                    sw.Flush();
                }catch (Exception ex)
                {
                    Console.WriteLine("Error notifying foreground changes.");
                    Console.WriteLine(ex.ToString());
                    Environment.Exit(1);
                }
                Console.WriteLine("Notified.");
                Thread.Sleep(2500);
            }
        }

        private static EventWaitHandle eventWaitHandle;

        public static void WinEventProc(HWINEVENTHOOK hWinEventHook, uint @event, HWND hwnd, int idObject, int idChild, uint idEventThread, uint dwmsEventTime)
        {
            eventWaitHandle.Set();
        }
    }

    public class Win32Window
    {
        private readonly HWND _hWnd;
        private string _title;
        private string _processName;
        private string _processName2;
        private uint _pid;
        internal Win32Window(HWND handle)
        {
            _hWnd = handle;
        }
        public string Title => _title ?? (_title = getWindowTitle());
        private string getWindowTitle()
        {
            int len = GetWindowTextLength(_hWnd) * 3;
            StringBuilder sb = new StringBuilder(len + 10);
            GetWindowText(_hWnd, sb, len + 10);
            return sb.ToString();
        }
        public uint ProcessId => _pid is 0 ? (_pid = GetProcessIdCore()) : _pid;
        public string ProcessName => _processName ?? (_processName = getProcessPath((int)ProcessId));
        public string ProcessNamePlain => _processName2 ?? (_processName2 = getProcessPath2((int)ProcessId));
        private string getProcessPath(int pid)
        {
            try
            {
                return Process.GetProcessById(pid).MainModule.FileName;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Cannot get process name: " + ex);
                try
                {
                    return Process.GetProcessById(pid).ProcessName;
                }
                catch (Exception ex2)
                {
                    Console.WriteLine("Cannot get process name again: " + ex2);
                }
            }
            return "[PID] " + pid;
        }
        private string getProcessPath2(int pid)
        {

            try
            {
                return Process.GetProcessById(pid).ProcessName;
            }
            catch (Exception ex2)
            {
                Console.WriteLine("Cannot get process name again: " + ex2);
            }

            return "[PID] " + pid;
        }
        private uint GetProcessIdCore()
        {
            uint pid;
            GetWindowThreadProcessId(_hWnd, out pid);
            return pid;
        }
    }

}
